/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package HGR;

import HGR.Learning.Histograms;
import HGR.Learning.InteresPoint;
import HGR.Learning.ManageDataSet;
import HGR.Learning.Punto;
import OpenCV.cv;
import OpenCV.cv.IplImage;
import SIFT.SIFT_ExtractPointRoi;
import SIFT.util.Feature;
import SIFT.util.FloatArray2D;
import SURF.Save_Interest_Points_To_File;
import com.sun.jna.Pointer;
import hmm.Hmm;
import hmm.Model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 *
 * @author Warrior3D
 */
public class test_videos {

    public static void main(String[] args)
    {
       // readVideoTest();
       // histogram();
      HmmTest();
    }

    public static void HmmTest()
    {
        int NumGestos = 5;
        int NumObsG = 10;

        
        Punto[][] Observaciones = new Punto[NumGestos][NumObsG];
        int u,v;
        for(u=0; u<Observaciones.length; u++)
        {
            for(v=0; v<Observaciones[u].length; v++)
            {
                //Observaciones[u][v] = (Hmm.Iniciar(Angles[a], Descriptors[d], filename))[(Observaciones[u].length * u)+v];
                Observaciones[u][v] = (Hmm.Iniciar(10, "SIFT", "Videos_test/Histograms"))[(Observaciones[u].length * u)+v];
            }
        }

        Model[] l = LoadModels();

        float[][] MxConfusion = new float[NumGestos][NumGestos];
        float[] pGest = new float[NumGestos];
        float minVal = Float.MAX_VALUE;
        int minId = -1;
        int i,w;

        for(u=0; u<Observaciones.length; u++)
        {            
            for(v=0; v<Observaciones[u].length; v++)
            {
                minVal = Float.MAX_VALUE;
                minId = -1;
                    for(w=0; w<Observaciones.length; w++)
                    {
                         pGest[w] = Hmm.CalcularProbabilidad(l[w], Observaciones[u][v].MaxiHist );
                    }

                    for(w=0; w<Observaciones.length; w++)
                    {
                        if(pGest[w] <  minVal)
                        {
                            minVal = pGest[w];
                            minId = w;
                        }
                    }
                    Observaciones[u][v].m = minId;
                    MxConfusion[u][minId]++;
            }
        }

        System.out.println();
        for(u=0; u<MxConfusion.length; u++)
        {
            for(v=0; v<MxConfusion[u].length; v++)
            {
                System.out.print(MxConfusion[u][v]+" ");
            }
            System.out.println();
        }
        System.out.println();
        //System.exit(0);
    }
    public static Model[] LoadModels()
    {
        ArrayList<String> ModelFile = new ArrayList<String>();
        Core.ListDir("Modelos", ModelFile, ".hmm");
        //Collections.shuffle(ModelFile);
        System.out.println(ModelFile);
        Model[] Mod = new Model[ModelFile.size()];
        int i;
        for(i=0; i<ModelFile.size(); i++)
        {
            Mod[i] = ReadModelFile(ModelFile.get(i), 15);
        }

        return Mod;
    }
    //--------------------------------------------------
    /**
     * Lee los archivos y devuelve el modelo de Markov
     * @param filename Nombre del archivo
     * @param DivAngle Número de división de ángulos
     * @return Modelo de Markov
     */
    public static Model ReadModelFile(String filename, int DivAngle)
    {

        File archivo = null;
        InputStreamReader fr = null;
        BufferedReader br = null;
        int n=0;
        String[] m = new String[0];
        float[][] a = new float[n][n];
        float[][] b = new float[n][360/DivAngle];
        float[] pi = new float[n];
        try
        {
            archivo = new File(filename);
            fr = new InputStreamReader(new FileInputStream(archivo), "UTF-8");
            br = new BufferedReader(fr);
            // Lectura del fichero
            String linea;
            String[] part;
            int l = 0;
            //Mientras halla lineas en el archivo
            while((linea=br.readLine())!=null)
            {
                if(l==0)
                {
                    n = (Integer.parseInt(linea));
                    m = new String[360/DivAngle];
                    pi = new float[n];
                    a = new float[n][n];
                    b = new float[n][360/DivAngle];
                }
                if(l==1)
                {
                    part = linea.split(" ");
                    for(int i=0; i<360/DivAngle; i++)
                    {
                        m[i]=part[i];
                    }

                }
                if(linea.intern()=="#Pi")
                {
                    linea=br.readLine();
                    part = linea.split(" ");
                    for(int i=0; i<n; i++)
                    {
                        pi[i]=(Float.valueOf(part[i]));
                    }
                }
                if(linea.intern()=="#A")
                {
                    for(int i=0; i<n; i++)
                    {
                        linea=br.readLine();
                        part = linea.split(" ");
                        for(int j=0; j<n; j++)
                        {
                        a[i][j]=(Float.valueOf(part[j]));
                        }
                    }
                }
                if(linea.intern()=="#B")
                {
                    for(int i=0; i<n; i++)
                    {
                        linea=br.readLine();
                        part = linea.split(" ");
                        for(int j=0; j<m.length; j++)
                        {
                        b[i][j]=(Float.valueOf(part[j]));
                        }
                    }
                }
                l++;
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            //Cerrar el Archivo
            try
            {
                if( null != fr )
                {
                    fr.close();
                }
            }
            catch(Exception e2)
            {
                e2.printStackTrace();
            }
        }

        Model lambda = new  Model(n, m, a, b, pi);
        return lambda;
    }


    public static void readVideoTest()
    {
        cv.loadHighgui();
        cv.loadCv();
        cv.loadCxcore();
        String full_path;
        ArrayList<String> Videos = new ArrayList<String>();
        ManageDataSet.ListDir("Videos_test", Videos, ".avi");
        //ListDir("../DataSet", Videos, ".avi");  //Dirección del DataSet

        List<Feature> ipts;
        int n;
        for(n = 0; n < Videos.size(); n++)
        {
            full_path = Videos.get(n);
            System.out.println("Video "+(n+1)+": \""+full_path+"\"");
            ManageDataSet.VideoFile(full_path);
            double fps = cv.GetCaptureProperty(ManageDataSet.camDev, cv.CV_CAP_PROP_FPS);
            System.out.println("Fps: "+fps+"\n");
            ManageDataSet.Iniciar();
            byte[] bufferByte = new byte[ManageDataSet.L];
            int time=1;


            //Bucle de proceso frame a frame
            while(true)
            {

                Pointer ptr_ima = cv.queryFrame(ManageDataSet.camDev);
                if(ptr_ima == null)
                    break;
                ManageDataSet.image_ptr = new IplImage(ptr_ima);
                cv.cvtColor(ManageDataSet.image_ptr.getPointer(), ManageDataSet.image_gray, cv.CV_BGR2GRAY);
                bufferByte = Core.Pointer2Byte(ManageDataSet.image_gray);
                for(int k=0; k<ManageDataSet.L; k++)
                {
                    if(bufferByte[k]<0)
                        ManageDataSet.buffer[k] = bufferByte[k] & 255;
                    else
                        ManageDataSet.buffer[k] = bufferByte[k];
                }
                System.arraycopy(ManageDataSet.buffer, 0, ManageDataSet.bufferOrigin, 0, ManageDataSet.L);
                ManageDataSet.buffer = Core.LowPassFilter(ManageDataSet.buffer, Core.lp_kernel,ManageDataSet.W, ManageDataSet.H);
                ManageDataSet.buffer = Core.MedianFilter(ManageDataSet.buffer, 3, ManageDataSet.W, ManageDataSet.H);
                Core.BackgroundSubtractionLearning(ManageDataSet.buffer, ManageDataSet.bufferBg, ManageDataSet.bufferBgS, ManageDataSet.avgBG, ManageDataSet.varBG, ManageDataSet.Threshold);
                ManageDataSet.bufferBgS = Core.ErosionFilter(Core.kernel5_Circle, ManageDataSet.bufferBgS, ManageDataSet.W, ManageDataSet.H);
                ManageDataSet.bufferBgS = Core.DilatationFilter(Core.kernel5_Circle, ManageDataSet.bufferBgS, ManageDataSet.W, ManageDataSet.H);
                float[] labels = Core.LabeledRegions(ManageDataSet.img_label, ManageDataSet.bufferBgS, ManageDataSet.W, ManageDataSet.H);
                Core.RemoveRegions(ManageDataSet.img_label, labels,ManageDataSet.W,ManageDataSet.H);

                ManageDataSet.img_label = Core.DilatationFilter(Core.kernel5_Circle, ManageDataSet.img_label, ManageDataSet.W, ManageDataSet.H);

                ManageDataSet.img_label = Core.MaskImage(ManageDataSet.img_label, ManageDataSet.bufferOrigin);

                FloatArray2D Desc2 = new FloatArray2D(ManageDataSet.img_label, ManageDataSet.W, ManageDataSet.H);
                SIFT_ExtractPointRoi.run(Desc2);
                ipts = SIFT_ExtractPointRoi.getLastResult();

                //=======
                Save_Interest_Points_To_File FilePoints = new Save_Interest_Points_To_File();
                //FilePoints.SurfFile(time, full_path);
                FilePoints.SiftFile(time, full_path);
                time++;
            }
        }
    }


    public static void histogram()
    {
        
        int[] frameCount = new int[50];
        int[][] HistogramsSIFT;
        ArrayList<String> DescriptoresSiftFile = new ArrayList<String>();
        
        ListDir("Videos_test/Descriptors", DescriptoresSiftFile, ".sift",frameCount,0,0);        

        ArrayList<InteresPoint> PuntosSIFT = new ArrayList<InteresPoint>();        
        ArrayList<InteresPoint> FilePoints = new ArrayList<InteresPoint>();

        int counti = 0;
        int Angulos[] = {15};
        int t,h,v,u;
        int VideoFCount = 0;
        int Div_Frames = 10;
        int Length_sum =0;
        // Para todos los videos
        for(v=0; v<frameCount.length; v++)
        {            

            HistogramsSIFT = new int[Angulos.length][];
                for(u=0; u<HistogramsSIFT.length; u++){
                    HistogramsSIFT[u] = new int[Div_Frames];}


            // Por cada Angulos
            for(h=0; h<Angulos.length; h++)
            {
                //Para todos los frames del video

                Length_sum = 0;                
                float[] _HistogramsSIFT = new float[360/Angulos[h]];

                for(t=0; t<Div_Frames; t++)
                {
                    int Div_Res = frameCount[v]%Div_Frames;
                    int Div_Int = (int)(frameCount[v]/Div_Frames);
                    int[] Length_Histograms = new int[Div_Frames];

                    for(u=0; u<Length_Histograms.length; u++)
                    {
                        Length_Histograms[u] = Div_Int;
                        if(u < Div_Res)
                            Length_Histograms[u] += 1;
                    }

                    for(u=0; u<Length_Histograms[t]; u++)
                    {
                        FilePoints = Histograms.ReadFilePoints(DescriptoresSiftFile.get(VideoFCount + (Length_sum+u)));
                        if(FilePoints.size() > 0)
                        {
                            Histograms.Histogram(_HistogramsSIFT, PuntosSIFT, FilePoints, Angulos[h]);
                            PuntosSIFT.clear();
                            PuntosSIFT.addAll(FilePoints);
                        }
                    }
                    Length_sum += Length_Histograms[t];                    

                    HistogramsSIFT[h][t] = Hmm.PMax(_HistogramsSIFT);
                    Arrays.fill(_HistogramsSIFT, 0.0f);

                        //PuntosSURF. = FilePoints.clone();

                }                
                PuntosSIFT.clear();
            }

            float a = Float.MIN_VALUE;
            VideoFCount += frameCount[v];
            //normalizeHistograms(HistogramsSURF, HistogramsSIFT);
            System.out.println("FIN "+DescriptoresSiftFile.get(counti));
            writeHistograms( HistogramsSIFT, DescriptoresSiftFile.get(counti));

            counti+=frameCount[v];
        }

    }

    /**
     * Escribe los histogramas de los puntos SIFT y SURF en un archivo
     * @param HistoSurf Histograma de ángulos para los puntos SURF
     * @param HistoSift Histograma de ángulos para los puntos SIFT
     * @param fileid Numero identificador del archivo
     */
    public static void writeHistograms(int[][] HistoSift, String Filename)
    {
        //Escribir los archivos de los histogramas

        String[] parts = Filename.split("/");

        String filename = "Videos_test/Histograms/"+parts[2]+".hist";
        try
        {
            PrintWriter out = new PrintWriter(filename, "UTF-8");
            //PrintWriter out = new PrintWriter( new OutputStreamWriter(System.out, "UTF-8"));


            
            int p;
            int q =0;
            out.println("#SIFT");            
            for(p=0; p<HistoSift.length; p++)
            {
                q=0;
                for(int t=0; t<HistoSift[p].length; t++)
                {
                    out.print( new String(HistoSift[p][t]+" "));
                    q += HistoSift[p][t];
                }
                System.out.println(q);
                out.print("\n");
            }

            out.flush();
            out.close();
        }
        //catch(FileNotFoundException e)
        catch(Exception e)
        {
            //IJ.error("SURF: savePointsToFile", e.getMessage());
        }
    }
    //--------------------------------------------------
    /**
     * Enlista los directorios y archivos de los puntos SIFT y SURF de cada frame de los videos
     * @param path Dirección de los archivos
     * @param dirs Lista donde se almacenan las direcciones
     * @param fileType Tipo de archivo que se enlista
     * @param FramesCount Array que almacena el número de frames por cada archivo
     * @param Fi Índice del video
     * @param level Nivel de profundidad de la función
     * @return
     */
    public static int ListDir(String path, ArrayList<String> dirs, String fileType,
            int[] FramesCount, int Fi, int level){
        String t = path;
        File f = new File(t);
        //int  = new int[312];

        if(f.isDirectory())
        {

            String[] fn = f.list();
            if(level > 0)
                FramesCount[Fi] = fn.length;

            level++;
            int i;
            for(i=0; i< fn.length; i++)
            {
                t = path+"/"+fn[i];
                Fi = ListDir(t, dirs,fileType,FramesCount,Fi, level);
            }
            level--;
            if(level == 1)
                Fi++;

        }else if(f.isFile())
        {
            if(path.substring(path.length()-fileType.length(), path.length()).equals(fileType)){
                dirs.add(path);
            }
        }

        return Fi;
    }

}
